/*
    $Header: /Windows/Shell/ShellExt.root/ShellExt/src/CCntxtMenu.h 2     08-07-24 0:20 Ken $
    $Log: /Windows/Shell/ShellExt.root/ShellExt/src/CCntxtMenu.h $
 * 
 * 2     08-07-24 0:20 Ken
 * add hook key (inject.dll setwindowshookex)
 *
 * 1     08-01-05 0:08 Ken

*/


#pragma once
#include "resource.h"       // main symbols

#include "ShellExt.h"
#include "CIShellExtImp.h"

#include "CJunction.h"
#include "CShellExtXML.h"

#include <string>

using namespace std;


//
// interface for submenu
class ICntxtSubMenu
{
// the init function
public:
    virtual BOOL VTgtInit(TCHAR* pszFl){return TRUE;};
    virtual BOOL VPreSrcInit(UINT uSrcNumb ){return TRUE;};
    virtual BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ ){return TRUE;};

// the menu function
public:
    virtual BOOL VIsCmdValid(DWORD dwId){return FALSE;};
    virtual const TCHAR* VGetMenuString(DWORD dwId)=0;
    virtual BOOL VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId)=0;
    virtual int GetMenuNumb()=0;
};

typedef ICntxtSubMenu* (*pfnCreateSubMenuInstance)();


//
// shell extention ICntxtMenu implement
//
// CCntxtMenu
class ATL_NO_VTABLE CCntxtMenu :
    public CComObjectRootEx<CComSingleThreadModel>,
    public CComCoClass<CCntxtMenu, &CLSID_CntxtMenu>,
    public IDispatchImpl<ICntxtMenu, &IID_ICntxtMenu, &LIBID_ShellExtLib, /*wMajor =*/ 1, /*wMinor =*/ 0>
    , public CIShellExtInitImp
    , public CIShlCntxMenuImp
{
//
// type defines
private:
    struct SubMenuInfo
    {
        ICntxtSubMenu* pSubMenu;
        int iCmdNumb;
        int iStartId;
    };

public:
    CCntxtMenu();
    ~CCntxtMenu();

DECLARE_REGISTRY_RESOURCEID(IDR_CNTXTMENU)


BEGIN_COM_MAP(CCntxtMenu)
    COM_INTERFACE_ENTRY(ICntxtMenu)
    COM_INTERFACE_ENTRY(IDispatch)
    COM_INTERFACE_ENTRY(IShellExtInit)
    COM_INTERFACE_ENTRY(IContextMenu)
END_COM_MAP()


    DECLARE_PROTECT_FINAL_CONSTRUCT()

    HRESULT FinalConstruct()
    {
        return S_OK;
    }

    void FinalRelease()
    {
    }

// the init implement
private:
    BOOL VTgtInit(TCHAR* pszFl);
    BOOL VPreSrcInit(UINT uSrcNumb );
    BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ );

// the context menu implement
private:
    BOOL VIsCmdValid(DWORD dwId);
    const TCHAR* VGetMenuString(DWORD dwId);
    BOOL VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId);
    DWORD VGetCmdNumb(){return m_iCmdNumb;};

private:
    BOOL  MapCntId2SubMenu(DWORD dwCntId, ICntxtSubMenu** ppSubMenu, DWORD* pdwSubMenuId);

private:
    SubMenuInfo* m_pSubMenuInfoS;
    bool* m_pValidSubMenuS;

    int m_iCmdNumb;


    static pfnCreateSubMenuInstance s_pfnCreateSubMenuInstanceS[];
    static int s_iSubMenuNumb;
};


//
// default implement for submenu
template<bool HAS_TARGET, int SRC_MAX_NUMB>
class CCntxtSubMenuImpl:public ICntxtSubMenu
{
public:
    CCntxtSubMenuImpl(const TCHAR** pszMenuS, int iMenuNumb, BOOL fInitStat)
        :m_pszCmdStrS(pszMenuS)
        ,m_iCmdNmb(iMenuNumb)
        ,m_fValid(fInitStat)
    {};

// the init function
public:
    virtual BOOL VTgtInit(TCHAR* pszFl)
    {
        if( (HAS_TARGET && (NULL!=pszFl))
            ||( (!HAS_TARGET) && (NULL==pszFl) ) )
        {
            m_strTgt=pszFl;
            return TRUE;
        }
        return FALSE;
    };
    virtual BOOL VPreSrcInit(UINT uSrcNumb )
    {return (uSrcNumb>SRC_MAX_NUMB)?FALSE:TRUE;};
    virtual BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ ){return TRUE;};

// the menu function
public:
    virtual BOOL VIsCmdValid(DWORD dwId)
    {
        if( (dwId<m_iCmdNmb)
            && ( FALSE!=m_fValid ) )
        {
            return TRUE;
        }

        return FALSE;
    };
    virtual const TCHAR* VGetMenuString(DWORD dwId){return m_pszCmdStrS[dwId];};
    virtual int GetMenuNumb(){return m_iCmdNmb;};

protected:
    CString m_strTgt;
    BOOL m_fValid;

private:
    const TCHAR** m_pszCmdStrS;
    int m_iCmdNmb;
};


class CCntxtSubMenuCmd :public CCntxtSubMenuImpl<false, 1>
{
public:
    CCntxtSubMenuCmd()
        :CCntxtSubMenuImpl<false, 1>(s_pszCmdStrS, s_iCmdNmb, FALSE)
    {};
// the init function
public:
    virtual BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ );

// the menu function
public:
    BOOL VIsCmdValid(DWORD dwId);
    BOOL VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId);

private:
    CString m_strCMD;
    CString m_strCMDExec;

// static members
public:
    static ICntxtSubMenu* CreateInstance();

private:
    static const TCHAR* s_pszCmdStrS[];
    static int s_iCmdNmb;
};



class CCntxtSubMenuDoXML :public CCntxtSubMenuImpl<false, 1>
{
public:
    CCntxtSubMenuDoXML()
        :CCntxtSubMenuImpl<false, 1>(s_pszCmdStrS, s_iCmdNmb, FALSE)
    {};

// the init function
public:
    BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ );

// the menu function
public:
    BOOL VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId);


private:
    CString m_strXMLFile;

// static members
public:
    static ICntxtSubMenu* CreateInstance();

private:
    static const TCHAR* s_pszCmdStrS[];
    static int s_iCmdNmb;
};


class CCntxtSubMenuJunct :public CCntxtSubMenuImpl<true, 0xffff>
{
public:
    CCntxtSubMenuJunct()
        :CCntxtSubMenuImpl<true, 0xffff>(s_pszCmdStrS, s_iCmdNmb, TRUE)
    {};

// the init function
public:
    BOOL VTgtInit(TCHAR* pszFl);
    BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ );

// the menu function
public:
    BOOL VIsCmdValid(DWORD dwId);
    BOOL VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId);


private:
    BOOL DoCreateJunct();
    BOOL DoDeleteJunct();

private:
    list<CString>    m_lststrSrcDir;
    list<CJunction>    m_lstJunct;

//
// static members
public:
    static ICntxtSubMenu* CreateInstance();

private:
    static const TCHAR* s_pszCmdStrS[];
    static int s_iCmdNmb;
};

class CCntxtSubMenuHdlnk :public CCntxtSubMenuImpl<true, 0xffff>
{
public:
    CCntxtSubMenuHdlnk()
        :CCntxtSubMenuImpl<true, 0xffff>(s_pszCmdStrS, s_iCmdNmb, FALSE)
    {};

// the init function
public:
    BOOL VSrcInit(UINT uSrcId, TCHAR* pszFl, BOOL fLoad=FALSE/*called by Load*/ );

// the menu function
public:
    BOOL VInvokeCommand(LPCMINVOKECOMMANDINFO pInfo, DWORD dwId);


private:
    list<CString>    m_lststrSrcFl;

// static members
public:
    static ICntxtSubMenu* CreateInstance();

private:
    static const TCHAR* s_pszCmdStrS[];
    static int s_iCmdNmb;
};

OBJECT_ENTRY_AUTO(__uuidof(CntxtMenu), CCntxtMenu)

